﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SpecialKey
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Search();
            if (!Hotkeys.RegisterHotKey(new WindowInteropHelper(this).Handle, 9999, (uint)Hotkeys.KeyFlags.MOD_ALT, 81))
                MessageBox.Show("热键注册失败");
            Hotkeys.InstallHotKeyHook(this);
        }

        private void Search(string keywords = null)
        {

            var pros = Process.GetProcesses();
            var items = pros.Where(s => !(s.ProcessName.Contains("Microsoft") || s.ProcessName.Contains("WINDOWS") || string.IsNullOrEmpty(s.MainWindowTitle) || s.ProcessName == "SpecialKey") && (keywords == null || (string.IsNullOrEmpty(keywords) || s.MainWindowTitle.Contains(keywords))))
                .Where(s =>
                {
                    try
                    {
                        ProcessModule m = s.MainModule;
                        if (m.FileName.Contains("Microsoft") || m.FileName.Contains("WINDOWS"))
                            return false;
                        return true;
                    }
                    catch
                    {
                        return false;
                    }

                })
                .Select(s =>
                    {
                        var name = s.ProcessName;
                        var title = s.MainWindowTitle;
                        var pid = s.Id;

                        var size = string.Format("{0:###,##0.00}MB", s.WorkingSet64 / 1024.0f / 1024.0f);

                        ImageSource icon = null;
                        StringBuilder sb = new();
                        try
                        {
                            sb.AppendLine("进程优先级：" + s.BasePriority + "（优先级类别： " + s.PriorityClass + "）");
                            ProcessModule m = s.MainModule;
                            sb.AppendLine("文件名：" + m.FileName);
                            sb.AppendLine("版本：" + m.FileVersionInfo.FileVersion);
                            sb.AppendLine("描述：" + m.FileVersionInfo.FileDescription);
                            sb.AppendLine("语言：" + m.FileVersionInfo.Language);
                            if (!string.IsNullOrEmpty(m.FileName))
                                icon = GetIcon(m.FileName, true, false);
                        }
                        catch { sb.AppendLine("无法获取详细信息"); }
                        return new { size, title, name, s.Id, Other = sb.ToString().Trim('\n').Trim('\r'), Icon = icon };
                    }).ToList();


            var ids = items.Select(s => s.Id);
            //从标记列表移除不存在的进程
            SkItem.ProcessIds = SkItem.ProcessIds.Where(s => ids.Contains(s.Key)).ToDictionary(s => s.Key, s => s.Value);

            resultList.Children.Clear();
            var orderList = new List<SkItem>();
            foreach (var item in items)
            {
                var d = new SkItem
                {
                    Title = item.title,
                    Id = item.Id,
                    ToolTip = item.Other,
                    Class = item.name,
                    WorkingSet = item.size
                };
                if (SkItem.ProcessIds.Keys.Contains(item.Id))
                    d.Mark = 1;
                else
                    d.Mark = 0;
                d.imgIcon.Source = item.Icon;
                orderList.Add(d);
            }
            foreach (var item in orderList.OrderByDescending(s => s.Mark))
                resultList.Children.Add(item);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Hide();
            Hotkeys.Show = false;
            e.Cancel = true;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Search(tbKeywords.Text);
        }
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("确认关闭", "系统提示", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                Application.Current.Shutdown(0);

        }

        public static ImageSource GetIcon(string path, bool smallIcon, bool isDirectory)
        {
            // SHGFI_USEFILEATTRIBUTES takes the file name and attributes into account if it doesn't exist
            uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
            if (smallIcon)
                flags |= SHGFI_SMALLICON;

            uint attributes = FILE_ATTRIBUTE_NORMAL;
            if (isDirectory)
                attributes |= FILE_ATTRIBUTE_DIRECTORY;

            SHFILEINFO shfi;
            if (0 != SHGetFileInfo(
                        path, attributes, out shfi, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), flags))
            {
                return Imaging.CreateBitmapSourceFromHIcon(
                            shfi.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            }
            return null;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        }

        [DllImport("shell32")]
        private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags);

        private const uint FILE_ATTRIBUTE_READONLY = 0x00000001;
        private const uint FILE_ATTRIBUTE_HIDDEN = 0x00000002;
        private const uint FILE_ATTRIBUTE_SYstem = 0x00000004;
        private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
        private const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
        private const uint FILE_ATTRIBUTE_DEVICE = 0x00000040;
        private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
        private const uint FILE_ATTRIBUTE_TEMPORARY = 0x00000100;
        private const uint FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200;
        private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400;
        private const uint FILE_ATTRIBUTE_COMPRESSED = 0x00000800;
        private const uint FILE_ATTRIBUTE_OFFLINE = 0x00001000;
        private const uint FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
        private const uint FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
        private const uint FILE_ATTRIBUTE_VIRTUAL = 0x00010000;

        private const uint SHGFI_ICON = 0x000000100;     // get icon
        private const uint SHGFI_DISPLAYNAME = 0x000000200;     // get display name
        private const uint SHGFI_TYPENAME = 0x000000400;     // get type name
        private const uint SHGFI_ATTRIBUTES = 0x000000800;     // get attributes
        private const uint SHGFI_ICONLOCATION = 0x000001000;     // get icon location
        private const uint SHGFI_EXETYPE = 0x000002000;     // return exe type
        private const uint SHGFI_SYSICONINDEX = 0x000004000;     // get system icon index
        private const uint SHGFI_LINKOVERLAY = 0x000008000;     // put a link overlay on icon
        private const uint SHGFI_SELECTED = 0x000010000;     // show icon in selected state
        private const uint SHGFI_ATTR_SPECIFIED = 0x000020000;     // get only specified attributes
        private const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
        private const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
        private const uint SHGFI_OPENICON = 0x000000002;     // get open icon
        private const uint SHGFI_SHELLICONSIZE = 0x000000004;     // get shell size icon
        private const uint SHGFI_PIDL = 0x000000008;     // pszPath is a pidl
        private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;     // use passed dwFileAttribute


    }
}
